package gla.centralhotel.dao;

import gla.centralhotel.dao.interfaces.IRoomDAO;
import gla.centralhotel.exception.CollectionRetrieverException;
import gla.centralhotel.exception.IllegalRoomNumberException;
import gla.centralhotel.model.Hotel;
import gla.centralhotel.model.Room;
import gla.centralhotel.model.RoomType;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 *
 * @author Rivo
 */
@Stateless
public class RoomDAO implements IRoomDAO {

    @PersistenceContext
    private EntityManager em;

    private Room create(Room room) {
        em.persist(room);
        return room;
    }

    private Room edit(Room room) {
        em.merge(room);
        return room;
    }

    @Override
    public void remove(Room room) {
        em.remove(em.merge(room));
    }

    private Room find(Object id) {
        return em.find(gla.centralhotel.model.Room.class, id);
    }

    private List<Room> findAll() {
        return em.createQuery("select object(o) from Room as o").getResultList();
    }

    /**
     * meme effet que la methode find(Object id) a l'exeption que les attributs transient
     * roomType et hotelName
     * sont remplit par les donnée de la base
     * @param id
     * @return
     */
    @Override
    public Room find_(Object id) {
        Room r = this.find(id);
        r.setHotelName(r.getRefHotel().getName());
        r.setRoomType(r.getRefRoomType().getType());
        return r;
    }

    /**
     * meme effet que la methode findAll() a l'exeption que les attribut transiant
     * roomType et hotelName
     * sont remplit par les donnée de la base
     * @return
     */
    @Override
    public List<Room> findAll_() {
        List<Room> liste = this.findAll();
        for (int i = 0; i < liste.size(); i++) {
            Room r = liste.get(i);
            Hotel h = r.getRefHotel();
            RoomType t = r.getRefRoomType();

            r.setHotelName(h.getName());
            r.setRoomType(t.getType());

            liste.set(i, r);
        }

        return liste;
    }

    /**
     * Recupere toutes les chambres d'un type
     * @param hotel
     * @return
     * @throws gla.centralhotel.exception.CollectionRetrieverException
     */
    @Override
    public ArrayList<Room> getAllRoomByType(RoomType type) throws CollectionRetrieverException {
        String query = "select rm from Room as rm where rm.refRoomType = :refRoomType";
        Query q = em.createQuery(query);
        q.setParameter("refRoomType", type);

        try {
            List<Room> liste = q.getResultList();
            for (int i = 0; i < liste.size(); i++) {
                Room r = liste.get(i);
                Hotel h = r.getRefHotel();
                RoomType t = r.getRefRoomType();

                r.setHotelName(h.getName());
                r.setRoomType(t.getType());

                liste.set(i, r);
            }
            return new ArrayList(liste);
        } catch (IllegalStateException ex) {
            ex.printStackTrace();
            throw new CollectionRetrieverException("Erreur de recuperation des chambres d'un type");
        }
    }

    /**
     * Recupere toutes les chambres d'un hotel
     * @param hotel
     * @return
     * @throws gla.centralhotel.exception.CollectionRetrieverException
     */
    @Override
    public ArrayList<Room> getAllRoomByHotel(Hotel hotel) throws CollectionRetrieverException {
        String query = "select rm from Room as rm where rm.refHotel = :refHotel";
        Query q = em.createQuery(query);
        q.setParameter("refHotel", hotel);

        try {
            List<Room> liste = q.getResultList();
            for (int i = 0; i < liste.size(); i++) {
                Room r = liste.get(i);
                Hotel h = r.getRefHotel();
                RoomType t = r.getRefRoomType();

                r.setHotelName(h.getName());
                r.setRoomType(t.getType());

                liste.set(i, r);
            }
            return new ArrayList(liste);
        } catch (IllegalStateException ex) {
            ex.printStackTrace();
            throw new CollectionRetrieverException("Erreur de recuperation des chambres d'un hotel");
        }
    }

    /**
     * MAJ la chambre(id + num chbr) si le numero de l'hotel existe deja
     * Sinon ajouter la chambre
     * @param room
     * @return
     */
    @Override
    public Room saveRoom(Room room) throws IllegalRoomNumberException {
        String query = "select rm from Room as rm where rm.refHotel = :refHotel and rm.number = :num";
        Query q = em.createQuery(query);
        q.setParameter("refHotel", room.getRefHotel());
        q.setParameter("num", room.getNumber());
        List<Room> rmList = q.getResultList();
        if (rmList.size() == 0) {
            return create(room);
        } else if (rmList.size() == 1 && room.getId() != null && room.getId().equals(rmList.iterator().next().getId())) {
            return edit(room);
        } else {
            throw new IllegalRoomNumberException("Erreur!! le numero de la chambre existe deja");
        }
    }
}
